/* Anubis Cipher
Copyright (C) Paulo S. L. M. Barreto.
Copyright (C) Vincent Rijmen.
Copyright (C) 2004 Aaron Grothe.
Copyright (C) 2011-2018 Manuel Sainz de Baranda y Goñi.
Released under the terms of the GNU Lesser General Public License v3. */

#if defined(CIPHER_ANUBIS_HIDE_API)
#	define CIPHER_ANUBIS_API static
#elif defined(CIPHER_ANUBIS_STATIC)
#	define CIPHER_ANUBIS_API
#else
#	define CIPHER_ANUBIS_API Z_API_EXPORT
#endif

#if defined(CIPHER_ANUBIS_HIDE_ABI)
#	define CIPHER_ANUBIS_ABI static
#elif defined(CIPHER_ANUBIS_STATIC)
#	define CIPHER_ANUBIS_ABI
#else
#	define CIPHER_ANUBIS_ABI Z_API_EXPORT
#endif

#define CIPHER_ANUBIS_OMIT_FUNCTION_PROTOTYPES

#if defined(CIPHER_ANUBIS_USE_LOCAL_HEADER)
#	include "Anubis"
#else
#	include <cipher/Anubis.h>
#endif

#include <Z/functions/base/value.h>

#define MAXIMUM_N	    10
#define MAXIMUM_ROUND_COUNT (8 + MAXIMUM_N)

#define C(value) Z_UINT32(0x##value)

static zuint32 const t0[256] = {
	C(BA69D2BB), C(54A84DE5), C(2F5EBCE2), C(74E8CD25),
	C(53A651F7), C(D3BB6BD0), C(D2B96FD6), C(4D9A29B3),
	C(50A05DFD), C(AC458ACF), C(8D070E09), C(BF63C6A5),
	C(70E0DD3D), C(52A455F1), C(9A29527B), C(4C982DB5),
	C(EAC98F46), C(D5B773C4), C(97336655), C(D1BF63DC),
	C(3366CCAA), C(51A259FB), C(5BB671C7), C(A651A2F3),
	C(DEA15FFE), C(48903DAD), C(A84D9AD7), C(992F5E71),
	C(DBAB4BE0), C(3264C8AC), C(B773E695), C(FCE5D732),
	C(E3DBAB70), C(9E214263), C(913F7E41), C(9B2B567D),
	C(E2D9AF76), C(BB6BD6BD), C(4182199B), C(6EDCA579),
	C(A557AEF9), C(CB8B0B80), C(6BD6B167), C(95376E59),
	C(A15FBEE1), C(F3FBEB10), C(B17FFE81), C(0204080C),
	C(CC851792), C(C49537A2), C(1D3A744E), C(14285078),
	C(C39B2BB0), C(63C69157), C(DAA94FE6), C(5DBA69D3),
	C(5FBE61DF), C(DCA557F2), C(7DFAE913), C(CD871394),
	C(7FFEE11F), C(5AB475C1), C(6CD8AD75), C(5CB86DD5),
	C(F7F3FB08), C(264C98D4), C(FFE3DB38), C(EDC79354),
	C(E8CD874A), C(9D274E69), C(6FDEA17F), C(8E010203),
	C(19326456), C(A05DBAE7), C(F0FDE71A), C(890F1E11),
	C(0F1E3C22), C(070E1C12), C(AF4386C5), C(FBEBCB20),
	C(08102030), C(152A547E), C(0D1A342E), C(04081018),
	C(01020406), C(64C88D45), C(DFA35BF8), C(76ECC529),
	C(79F2F90B), C(DDA753F4), C(3D7AF48E), C(162C5874),
	C(3F7EFC82), C(376EDCB2), C(6DDAA973), C(3870E090),
	C(B96FDEB1), C(73E6D137), C(E9CF834C), C(356AD4BE),
	C(55AA49E3), C(71E2D93B), C(7BF6F107), C(8C050A0F),
	C(72E4D531), C(880D1A17), C(F6F1FF0E), C(2A54A8FC),
	C(3E7CF884), C(5EBC65D9), C(274E9CD2), C(468C0589),
	C(0C183028), C(65CA8943), C(68D0BD6D), C(61C2995B),
	C(03060C0A), C(C19F23BC), C(57AE41EF), C(D6B17FCE),
	C(D9AF43EC), C(58B07DCD), C(D8AD47EA), C(66CC8549),
	C(D7B37BC8), C(3A74E89C), C(C88D078A), C(3C78F088),
	C(FAE9CF26), C(96316253), C(A753A6F5), C(982D5A77),
	C(ECC59752), C(B86DDAB7), C(C7933BA8), C(AE4182C3),
	C(69D2B96B), C(4B9631A7), C(AB4B96DD), C(A94F9ED1),
	C(67CE814F), C(0A14283C), C(478E018F), C(F2F9EF16),
	C(B577EE99), C(224488CC), C(E5D7B364), C(EEC19F5E),
	C(BE61C2A3), C(2B56ACFA), C(811F3E21), C(1224486C),
	C(831B362D), C(1B366C5A), C(0E1C3824), C(23468CCA),
	C(F5F7F304), C(458A0983), C(214284C6), C(CE811F9E),
	C(499239AB), C(2C58B0E8), C(F9EFC32C), C(E6D1BF6E),
	C(B671E293), C(2850A0F0), C(172E5C72), C(8219322B),
	C(1A34685C), C(8B0B161D), C(FEE1DF3E), C(8A09121B),
	C(09122436), C(C98F038C), C(87132635), C(4E9C25B9),
	C(E1DFA37C), C(2E5CB8E4), C(E4D5B762), C(E0DDA77A),
	C(EBCB8B40), C(903D7A47), C(A455AAFF), C(1E3C7844),
	C(85172E39), C(60C09D5D), C(00000000), C(254A94DE),
	C(F4F5F702), C(F1FFE31C), C(94356A5F), C(0B162C3A),
	C(E7D3BB68), C(75EAC923), C(EFC39B58), C(3468D0B8),
	C(3162C4A6), C(D4B577C2), C(D0BD67DA), C(86112233),
	C(7EFCE519), C(AD478EC9), C(FDE7D334), C(2952A4F6),
	C(3060C0A0), C(3B76EC9A), C(9F234665), C(F8EDC72A),
	C(C6913FAE), C(13264C6A), C(060C1814), C(050A141E),
	C(C59733A4), C(11224466), C(77EEC12F), C(7CF8ED15),
	C(7AF4F501), C(78F0FD0D), C(366CD8B4), C(1C387048),
	C(3972E496), C(59B279CB), C(18306050), C(56AC45E9),
	C(B37BF68D), C(B07DFA87), C(244890D8), C(204080C0),
	C(B279F28B), C(9239724B), C(A35BB6ED), C(C09D27BA),
	C(44880D85), C(62C49551), C(10204060), C(B475EA9F),
	C(84152A3F), C(43861197), C(933B764D), C(C2992FB6),
	C(4A9435A1), C(BD67CEA9), C(8F030605), C(2D5AB4EE),
	C(BC65CAAF), C(9C254A6F), C(6AD4B561), C(40801D9D),
	C(CF831B98), C(A259B2EB), C(801D3A27), C(4F9E21BF),
	C(1F3E7C42), C(CA890F86), C(AA4992DB), C(42841591)
};

static zuint32 const t1[256] = {
	C(69BABBD2), C(A854E54D), C(5E2FE2BC), C(E87425CD),
	C(A653F751), C(BBD3D06B), C(B9D2D66F), C(9A4DB329),
	C(A050FD5D), C(45ACCF8A), C(078D090E), C(63BFA5C6),
	C(E0703DDD), C(A452F155), C(299A7B52), C(984CB52D),
	C(C9EA468F), C(B7D5C473), C(33975566), C(BFD1DC63),
	C(6633AACC), C(A251FB59), C(B65BC771), C(51A6F3A2),
	C(A1DEFE5F), C(9048AD3D), C(4DA8D79A), C(2F99715E),
	C(ABDBE04B), C(6432ACC8), C(73B795E6), C(E5FC32D7),
	C(DBE370AB), C(219E6342), C(3F91417E), C(2B9B7D56),
	C(D9E276AF), C(6BBBBDD6), C(82419B19), C(DC6E79A5),
	C(57A5F9AE), C(8BCB800B), C(D66B67B1), C(3795596E),
	C(5FA1E1BE), C(FBF310EB), C(7FB181FE), C(04020C08),
	C(85CC9217), C(95C4A237), C(3A1D4E74), C(28147850),
	C(9BC3B02B), C(C6635791), C(A9DAE64F), C(BA5DD369),
	C(BE5FDF61), C(A5DCF257), C(FA7D13E9), C(87CD9413),
	C(FE7F1FE1), C(B45AC175), C(D86C75AD), C(B85CD56D),
	C(F3F708FB), C(4C26D498), C(E3FF38DB), C(C7ED5493),
	C(CDE84A87), C(279D694E), C(DE6F7FA1), C(018E0302),
	C(32195664), C(5DA0E7BA), C(FDF01AE7), C(0F89111E),
	C(1E0F223C), C(0E07121C), C(43AFC586), C(EBFB20CB),
	C(10083020), C(2A157E54), C(1A0D2E34), C(08041810),
	C(02010604), C(C864458D), C(A3DFF85B), C(EC7629C5),
	C(F2790BF9), C(A7DDF453), C(7A3D8EF4), C(2C167458),
	C(7E3F82FC), C(6E37B2DC), C(DA6D73A9), C(703890E0),
	C(6FB9B1DE), C(E67337D1), C(CFE94C83), C(6A35BED4),
	C(AA55E349), C(E2713BD9), C(F67B07F1), C(058C0F0A),
	C(E47231D5), C(0D88171A), C(F1F60EFF), C(542AFCA8),
	C(7C3E84F8), C(BC5ED965), C(4E27D29C), C(8C468905),
	C(180C2830), C(CA654389), C(D0686DBD), C(C2615B99),
	C(06030A0C), C(9FC1BC23), C(AE57EF41), C(B1D6CE7F),
	C(AFD9EC43), C(B058CD7D), C(ADD8EA47), C(CC664985),
	C(B3D7C87B), C(743A9CE8), C(8DC88A07), C(783C88F0),
	C(E9FA26CF), C(31965362), C(53A7F5A6), C(2D98775A),
	C(C5EC5297), C(6DB8B7DA), C(93C7A83B), C(41AEC382),
	C(D2696BB9), C(964BA731), C(4BABDD96), C(4FA9D19E),
	C(CE674F81), C(140A3C28), C(8E478F01), C(F9F216EF),
	C(77B599EE), C(4422CC88), C(D7E564B3), C(C1EE5E9F),
	C(61BEA3C2), C(562BFAAC), C(1F81213E), C(24126C48),
	C(1B832D36), C(361B5A6C), C(1C0E2438), C(4623CA8C),
	C(F7F504F3), C(8A458309), C(4221C684), C(81CE9E1F),
	C(9249AB39), C(582CE8B0), C(EFF92CC3), C(D1E66EBF),
	C(71B693E2), C(5028F0A0), C(2E17725C), C(19822B32),
	C(341A5C68), C(0B8B1D16), C(E1FE3EDF), C(098A1B12),
	C(12093624), C(8FC98C03), C(13873526), C(9C4EB925),
	C(DFE17CA3), C(5C2EE4B8), C(D5E462B7), C(DDE07AA7),
	C(CBEB408B), C(3D90477A), C(55A4FFAA), C(3C1E4478),
	C(1785392E), C(C0605D9D), C(00000000), C(4A25DE94),
	C(F5F402F7), C(FFF11CE3), C(35945F6A), C(160B3A2C),
	C(D3E768BB), C(EA7523C9), C(C3EF589B), C(6834B8D0),
	C(6231A6C4), C(B5D4C277), C(BDD0DA67), C(11863322),
	C(FC7E19E5), C(47ADC98E), C(E7FD34D3), C(5229F6A4),
	C(6030A0C0), C(763B9AEC), C(239F6546), C(EDF82AC7),
	C(91C6AE3F), C(26136A4C), C(0C061418), C(0A051E14),
	C(97C5A433), C(22116644), C(EE772FC1), C(F87C15ED),
	C(F47A01F5), C(F0780DFD), C(6C36B4D8), C(381C4870),
	C(723996E4), C(B259CB79), C(30185060), C(AC56E945),
	C(7BB38DF6), C(7DB087FA), C(4824D890), C(4020C080),
	C(79B28BF2), C(39924B72), C(5BA3EDB6), C(9DC0BA27),
	C(8844850D), C(C4625195), C(20106040), C(75B49FEA),
	C(15843F2A), C(86439711), C(3B934D76), C(99C2B62F),
	C(944AA135), C(67BDA9CE), C(038F0506), C(5A2DEEB4),
	C(65BCAFCA), C(259C6F4A), C(D46A61B5), C(80409D1D),
	C(83CF981B), C(59A2EBB2), C(1D80273A), C(9E4FBF21),
	C(3E1F427C), C(89CA860F), C(49AADB92), C(84429115)
};

static zuint32 const t2[256] = {
	C(D2BBBA69), C(4DE554A8), C(BCE22F5E), C(CD2574E8),
	C(51F753A6), C(6BD0D3BB), C(6FD6D2B9), C(29B34D9A),
	C(5DFD50A0), C(8ACFAC45), C(0E098D07), C(C6A5BF63),
	C(DD3D70E0), C(55F152A4), C(527B9A29), C(2DB54C98),
	C(8F46EAC9), C(73C4D5B7), C(66559733), C(63DCD1BF),
	C(CCAA3366), C(59FB51A2), C(71C75BB6), C(A2F3A651),
	C(5FFEDEA1), C(3DAD4890), C(9AD7A84D), C(5E71992F),
	C(4BE0DBAB), C(C8AC3264), C(E695B773), C(D732FCE5),
	C(AB70E3DB), C(42639E21), C(7E41913F), C(567D9B2B),
	C(AF76E2D9), C(D6BDBB6B), C(199B4182), C(A5796EDC),
	C(AEF9A557), C(0B80CB8B), C(B1676BD6), C(6E599537),
	C(BEE1A15F), C(EB10F3FB), C(FE81B17F), C(080C0204),
	C(1792CC85), C(37A2C495), C(744E1D3A), C(50781428),
	C(2BB0C39B), C(915763C6), C(4FE6DAA9), C(69D35DBA),
	C(61DF5FBE), C(57F2DCA5), C(E9137DFA), C(1394CD87),
	C(E11F7FFE), C(75C15AB4), C(AD756CD8), C(6DD55CB8),
	C(FB08F7F3), C(98D4264C), C(DB38FFE3), C(9354EDC7),
	C(874AE8CD), C(4E699D27), C(A17F6FDE), C(02038E01),
	C(64561932), C(BAE7A05D), C(E71AF0FD), C(1E11890F),
	C(3C220F1E), C(1C12070E), C(86C5AF43), C(CB20FBEB),
	C(20300810), C(547E152A), C(342E0D1A), C(10180408),
	C(04060102), C(8D4564C8), C(5BF8DFA3), C(C52976EC),
	C(F90B79F2), C(53F4DDA7), C(F48E3D7A), C(5874162C),
	C(FC823F7E), C(DCB2376E), C(A9736DDA), C(E0903870),
	C(DEB1B96F), C(D13773E6), C(834CE9CF), C(D4BE356A),
	C(49E355AA), C(D93B71E2), C(F1077BF6), C(0A0F8C05),
	C(D53172E4), C(1A17880D), C(FF0EF6F1), C(A8FC2A54),
	C(F8843E7C), C(65D95EBC), C(9CD2274E), C(0589468C),
	C(30280C18), C(894365CA), C(BD6D68D0), C(995B61C2),
	C(0C0A0306), C(23BCC19F), C(41EF57AE), C(7FCED6B1),
	C(43ECD9AF), C(7DCD58B0), C(47EAD8AD), C(854966CC),
	C(7BC8D7B3), C(E89C3A74), C(078AC88D), C(F0883C78),
	C(CF26FAE9), C(62539631), C(A6F5A753), C(5A77982D),
	C(9752ECC5), C(DAB7B86D), C(3BA8C793), C(82C3AE41),
	C(B96B69D2), C(31A74B96), C(96DDAB4B), C(9ED1A94F),
	C(814F67CE), C(283C0A14), C(018F478E), C(EF16F2F9),
	C(EE99B577), C(88CC2244), C(B364E5D7), C(9F5EEEC1),
	C(C2A3BE61), C(ACFA2B56), C(3E21811F), C(486C1224),
	C(362D831B), C(6C5A1B36), C(38240E1C), C(8CCA2346),
	C(F304F5F7), C(0983458A), C(84C62142), C(1F9ECE81),
	C(39AB4992), C(B0E82C58), C(C32CF9EF), C(BF6EE6D1),
	C(E293B671), C(A0F02850), C(5C72172E), C(322B8219),
	C(685C1A34), C(161D8B0B), C(DF3EFEE1), C(121B8A09),
	C(24360912), C(038CC98F), C(26358713), C(25B94E9C),
	C(A37CE1DF), C(B8E42E5C), C(B762E4D5), C(A77AE0DD),
	C(8B40EBCB), C(7A47903D), C(AAFFA455), C(78441E3C),
	C(2E398517), C(9D5D60C0), C(00000000), C(94DE254A),
	C(F702F4F5), C(E31CF1FF), C(6A5F9435), C(2C3A0B16),
	C(BB68E7D3), C(C92375EA), C(9B58EFC3), C(D0B83468),
	C(C4A63162), C(77C2D4B5), C(67DAD0BD), C(22338611),
	C(E5197EFC), C(8EC9AD47), C(D334FDE7), C(A4F62952),
	C(C0A03060), C(EC9A3B76), C(46659F23), C(C72AF8ED),
	C(3FAEC691), C(4C6A1326), C(1814060C), C(141E050A),
	C(33A4C597), C(44661122), C(C12F77EE), C(ED157CF8),
	C(F5017AF4), C(FD0D78F0), C(D8B4366C), C(70481C38),
	C(E4963972), C(79CB59B2), C(60501830), C(45E956AC),
	C(F68DB37B), C(FA87B07D), C(90D82448), C(80C02040),
	C(F28BB279), C(724B9239), C(B6EDA35B), C(27BAC09D),
	C(0D854488), C(955162C4), C(40601020), C(EA9FB475),
	C(2A3F8415), C(11974386), C(764D933B), C(2FB6C299),
	C(35A14A94), C(CEA9BD67), C(06058F03), C(B4EE2D5A),
	C(CAAFBC65), C(4A6F9C25), C(B5616AD4), C(1D9D4080),
	C(1B98CF83), C(B2EBA259), C(3A27801D), C(21BF4F9E),
	C(7C421F3E), C(0F86CA89), C(92DBAA49), C(15914284)
};

static zuint32 const t3[256] = {
	C(BBD269BA), C(E54DA854), C(E2BC5E2F), C(25CDE874),
	C(F751A653), C(D06BBBD3), C(D66FB9D2), C(B3299A4D),
	C(FD5DA050), C(CF8A45AC), C(090E078D), C(A5C663BF),
	C(3DDDE070), C(F155A452), C(7B52299A), C(B52D984C),
	C(468FC9EA), C(C473B7D5), C(55663397), C(DC63BFD1),
	C(AACC6633), C(FB59A251), C(C771B65B), C(F3A251A6),
	C(FE5FA1DE), C(AD3D9048), C(D79A4DA8), C(715E2F99),
	C(E04BABDB), C(ACC86432), C(95E673B7), C(32D7E5FC),
	C(70ABDBE3), C(6342219E), C(417E3F91), C(7D562B9B),
	C(76AFD9E2), C(BDD66BBB), C(9B198241), C(79A5DC6E),
	C(F9AE57A5), C(800B8BCB), C(67B1D66B), C(596E3795),
	C(E1BE5FA1), C(10EBFBF3), C(81FE7FB1), C(0C080402),
	C(921785CC), C(A23795C4), C(4E743A1D), C(78502814),
	C(B02B9BC3), C(5791C663), C(E64FA9DA), C(D369BA5D),
	C(DF61BE5F), C(F257A5DC), C(13E9FA7D), C(941387CD),
	C(1FE1FE7F), C(C175B45A), C(75ADD86C), C(D56DB85C),
	C(08FBF3F7), C(D4984C26), C(38DBE3FF), C(5493C7ED),
	C(4A87CDE8), C(694E279D), C(7FA1DE6F), C(0302018E),
	C(56643219), C(E7BA5DA0), C(1AE7FDF0), C(111E0F89),
	C(223C1E0F), C(121C0E07), C(C58643AF), C(20CBEBFB),
	C(30201008), C(7E542A15), C(2E341A0D), C(18100804),
	C(06040201), C(458DC864), C(F85BA3DF), C(29C5EC76),
	C(0BF9F279), C(F453A7DD), C(8EF47A3D), C(74582C16),
	C(82FC7E3F), C(B2DC6E37), C(73A9DA6D), C(90E07038),
	C(B1DE6FB9), C(37D1E673), C(4C83CFE9), C(BED46A35),
	C(E349AA55), C(3BD9E271), C(07F1F67B), C(0F0A058C),
	C(31D5E472), C(171A0D88), C(0EFFF1F6), C(FCA8542A),
	C(84F87C3E), C(D965BC5E), C(D29C4E27), C(89058C46),
	C(2830180C), C(4389CA65), C(6DBDD068), C(5B99C261),
	C(0A0C0603), C(BC239FC1), C(EF41AE57), C(CE7FB1D6),
	C(EC43AFD9), C(CD7DB058), C(EA47ADD8), C(4985CC66),
	C(C87BB3D7), C(9CE8743A), C(8A078DC8), C(88F0783C),
	C(26CFE9FA), C(53623196), C(F5A653A7), C(775A2D98),
	C(5297C5EC), C(B7DA6DB8), C(A83B93C7), C(C38241AE),
	C(6BB9D269), C(A731964B), C(DD964BAB), C(D19E4FA9),
	C(4F81CE67), C(3C28140A), C(8F018E47), C(16EFF9F2),
	C(99EE77B5), C(CC884422), C(64B3D7E5), C(5E9FC1EE),
	C(A3C261BE), C(FAAC562B), C(213E1F81), C(6C482412),
	C(2D361B83), C(5A6C361B), C(24381C0E), C(CA8C4623),
	C(04F3F7F5), C(83098A45), C(C6844221), C(9E1F81CE),
	C(AB399249), C(E8B0582C), C(2CC3EFF9), C(6EBFD1E6),
	C(93E271B6), C(F0A05028), C(725C2E17), C(2B321982),
	C(5C68341A), C(1D160B8B), C(3EDFE1FE), C(1B12098A),
	C(36241209), C(8C038FC9), C(35261387), C(B9259C4E),
	C(7CA3DFE1), C(E4B85C2E), C(62B7D5E4), C(7AA7DDE0),
	C(408BCBEB), C(477A3D90), C(FFAA55A4), C(44783C1E),
	C(392E1785), C(5D9DC060), C(00000000), C(DE944A25),
	C(02F7F5F4), C(1CE3FFF1), C(5F6A3594), C(3A2C160B),
	C(68BBD3E7), C(23C9EA75), C(589BC3EF), C(B8D06834),
	C(A6C46231), C(C277B5D4), C(DA67BDD0), C(33221186),
	C(19E5FC7E), C(C98E47AD), C(34D3E7FD), C(F6A45229),
	C(A0C06030), C(9AEC763B), C(6546239F), C(2AC7EDF8),
	C(AE3F91C6), C(6A4C2613), C(14180C06), C(1E140A05),
	C(A43397C5), C(66442211), C(2FC1EE77), C(15EDF87C),
	C(01F5F47A), C(0DFDF078), C(B4D86C36), C(4870381C),
	C(96E47239), C(CB79B259), C(50603018), C(E945AC56),
	C(8DF67BB3), C(87FA7DB0), C(D8904824), C(C0804020),
	C(8BF279B2), C(4B723992), C(EDB65BA3), C(BA279DC0),
	C(850D8844), C(5195C462), C(60402010), C(9FEA75B4),
	C(3F2A1584), C(97118643), C(4D763B93), C(B62F99C2),
	C(A135944A), C(A9CE67BD), C(0506038F), C(EEB45A2D),
	C(AFCA65BC), C(6F4A259C), C(61B5D46A), C(9D1D8040),
	C(981B83CF), C(EBB259A2), C(273A1D80), C(BF219E4F),
	C(427C3E1F), C(860F89CA), C(DB9249AA), C(91158442)
};

static zuint32 const t4[256] = {
	C(BABABABA), C(54545454), C(2F2F2F2F), C(74747474),
	C(53535353), C(D3D3D3D3), C(D2D2D2D2), C(4D4D4D4D),
	C(50505050), C(ACACACAC), C(8D8D8D8D), C(BFBFBFBF),
	C(70707070), C(52525252), C(9A9A9A9A), C(4C4C4C4C),
	C(EAEAEAEA), C(D5D5D5D5), C(97979797), C(D1D1D1D1),
	C(33333333), C(51515151), C(5B5B5B5B), C(A6A6A6A6),
	C(DEDEDEDE), C(48484848), C(A8A8A8A8), C(99999999),
	C(DBDBDBDB), C(32323232), C(B7B7B7B7), C(FCFCFCFC),
	C(E3E3E3E3), C(9E9E9E9E), C(91919191), C(9B9B9B9B),
	C(E2E2E2E2), C(BBBBBBBB), C(41414141), C(6E6E6E6E),
	C(A5A5A5A5), C(CBCBCBCB), C(6B6B6B6B), C(95959595),
	C(A1A1A1A1), C(F3F3F3F3), C(B1B1B1B1), C(02020202),
	C(CCCCCCCC), C(C4C4C4C4), C(1D1D1D1D), C(14141414),
	C(C3C3C3C3), C(63636363), C(DADADADA), C(5D5D5D5D),
	C(5F5F5F5F), C(DCDCDCDC), C(7D7D7D7D), C(CDCDCDCD),
	C(7F7F7F7F), C(5A5A5A5A), C(6C6C6C6C), C(5C5C5C5C),
	C(F7F7F7F7), C(26262626), C(FFFFFFFF), C(EDEDEDED),
	C(E8E8E8E8), C(9D9D9D9D), C(6F6F6F6F), C(8E8E8E8E),
	C(19191919), C(A0A0A0A0), C(F0F0F0F0), C(89898989),
	C(0F0F0F0F), C(07070707), C(AFAFAFAF), C(FBFBFBFB),
	C(08080808), C(15151515), C(0D0D0D0D), C(04040404),
	C(01010101), C(64646464), C(DFDFDFDF), C(76767676),
	C(79797979), C(DDDDDDDD), C(3D3D3D3D), C(16161616),
	C(3F3F3F3F), C(37373737), C(6D6D6D6D), C(38383838),
	C(B9B9B9B9), C(73737373), C(E9E9E9E9), C(35353535),
	C(55555555), C(71717171), C(7B7B7B7B), C(8C8C8C8C),
	C(72727272), C(88888888), C(F6F6F6F6), C(2A2A2A2A),
	C(3E3E3E3E), C(5E5E5E5E), C(27272727), C(46464646),
	C(0C0C0C0C), C(65656565), C(68686868), C(61616161),
	C(03030303), C(C1C1C1C1), C(57575757), C(D6D6D6D6),
	C(D9D9D9D9), C(58585858), C(D8D8D8D8), C(66666666),
	C(D7D7D7D7), C(3A3A3A3A), C(C8C8C8C8), C(3C3C3C3C),
	C(FAFAFAFA), C(96969696), C(A7A7A7A7), C(98989898),
	C(ECECECEC), C(B8B8B8B8), C(C7C7C7C7), C(AEAEAEAE),
	C(69696969), C(4B4B4B4B), C(ABABABAB), C(A9A9A9A9),
	C(67676767), C(0A0A0A0A), C(47474747), C(F2F2F2F2),
	C(B5B5B5B5), C(22222222), C(E5E5E5E5), C(EEEEEEEE),
	C(BEBEBEBE), C(2B2B2B2B), C(81818181), C(12121212),
	C(83838383), C(1B1B1B1B), C(0E0E0E0E), C(23232323),
	C(F5F5F5F5), C(45454545), C(21212121), C(CECECECE),
	C(49494949), C(2C2C2C2C), C(F9F9F9F9), C(E6E6E6E6),
	C(B6B6B6B6), C(28282828), C(17171717), C(82828282),
	C(1A1A1A1A), C(8B8B8B8B), C(FEFEFEFE), C(8A8A8A8A),
	C(09090909), C(C9C9C9C9), C(87878787), C(4E4E4E4E),
	C(E1E1E1E1), C(2E2E2E2E), C(E4E4E4E4), C(E0E0E0E0),
	C(EBEBEBEB), C(90909090), C(A4A4A4A4), C(1E1E1E1E),
	C(85858585), C(60606060), C(00000000), C(25252525),
	C(F4F4F4F4), C(F1F1F1F1), C(94949494), C(0B0B0B0B),
	C(E7E7E7E7), C(75757575), C(EFEFEFEF), C(34343434),
	C(31313131), C(D4D4D4D4), C(D0D0D0D0), C(86868686),
	C(7E7E7E7E), C(ADADADAD), C(FDFDFDFD), C(29292929),
	C(30303030), C(3B3B3B3B), C(9F9F9F9F), C(F8F8F8F8),
	C(C6C6C6C6), C(13131313), C(06060606), C(05050505),
	C(C5C5C5C5), C(11111111), C(77777777), C(7C7C7C7C),
	C(7A7A7A7A), C(78787878), C(36363636), C(1C1C1C1C),
	C(39393939), C(59595959), C(18181818), C(56565656),
	C(B3B3B3B3), C(B0B0B0B0), C(24242424), C(20202020),
	C(B2B2B2B2), C(92929292), C(A3A3A3A3), C(C0C0C0C0),
	C(44444444), C(62626262), C(10101010), C(B4B4B4B4),
	C(84848484), C(43434343), C(93939393), C(C2C2C2C2),
	C(4A4A4A4A), C(BDBDBDBD), C(8F8F8F8F), C(2D2D2D2D),
	C(BCBCBCBC), C(9C9C9C9C), C(6A6A6A6A), C(40404040),
	C(CFCFCFCF), C(A2A2A2A2), C(80808080), C(4F4F4F4F),
	C(1F1F1F1F), C(CACACACA), C(AAAAAAAA), C(42424242)
};

static zuint32 const t5[256] = {
	C(00000000), C(01020608), C(02040C10), C(03060A18),
	C(04081820), C(050A1E28), C(060C1430), C(070E1238),
	C(08103040), C(09123648), C(0A143C50), C(0B163A58),
	C(0C182860), C(0D1A2E68), C(0E1C2470), C(0F1E2278),
	C(10206080), C(11226688), C(12246C90), C(13266A98),
	C(142878A0), C(152A7EA8), C(162C74B0), C(172E72B8),
	C(183050C0), C(193256C8), C(1A345CD0), C(1B365AD8),
	C(1C3848E0), C(1D3A4EE8), C(1E3C44F0), C(1F3E42F8),
	C(2040C01D), C(2142C615), C(2244CC0D), C(2346CA05),
	C(2448D83D), C(254ADE35), C(264CD42D), C(274ED225),
	C(2850F05D), C(2952F655), C(2A54FC4D), C(2B56FA45),
	C(2C58E87D), C(2D5AEE75), C(2E5CE46D), C(2F5EE265),
	C(3060A09D), C(3162A695), C(3264AC8D), C(3366AA85),
	C(3468B8BD), C(356ABEB5), C(366CB4AD), C(376EB2A5),
	C(387090DD), C(397296D5), C(3A749CCD), C(3B769AC5),
	C(3C7888FD), C(3D7A8EF5), C(3E7C84ED), C(3F7E82E5),
	C(40809D3A), C(41829B32), C(4284912A), C(43869722),
	C(4488851A), C(458A8312), C(468C890A), C(478E8F02),
	C(4890AD7A), C(4992AB72), C(4A94A16A), C(4B96A762),
	C(4C98B55A), C(4D9AB352), C(4E9CB94A), C(4F9EBF42),
	C(50A0FDBA), C(51A2FBB2), C(52A4F1AA), C(53A6F7A2),
	C(54A8E59A), C(55AAE392), C(56ACE98A), C(57AEEF82),
	C(58B0CDFA), C(59B2CBF2), C(5AB4C1EA), C(5BB6C7E2),
	C(5CB8D5DA), C(5DBAD3D2), C(5EBCD9CA), C(5FBEDFC2),
	C(60C05D27), C(61C25B2F), C(62C45137), C(63C6573F),
	C(64C84507), C(65CA430F), C(66CC4917), C(67CE4F1F),
	C(68D06D67), C(69D26B6F), C(6AD46177), C(6BD6677F),
	C(6CD87547), C(6DDA734F), C(6EDC7957), C(6FDE7F5F),
	C(70E03DA7), C(71E23BAF), C(72E431B7), C(73E637BF),
	C(74E82587), C(75EA238F), C(76EC2997), C(77EE2F9F),
	C(78F00DE7), C(79F20BEF), C(7AF401F7), C(7BF607FF),
	C(7CF815C7), C(7DFA13CF), C(7EFC19D7), C(7FFE1FDF),
	C(801D2774), C(811F217C), C(82192B64), C(831B2D6C),
	C(84153F54), C(8517395C), C(86113344), C(8713354C),
	C(880D1734), C(890F113C), C(8A091B24), C(8B0B1D2C),
	C(8C050F14), C(8D07091C), C(8E010304), C(8F03050C),
	C(903D47F4), C(913F41FC), C(92394BE4), C(933B4DEC),
	C(94355FD4), C(953759DC), C(963153C4), C(973355CC),
	C(982D77B4), C(992F71BC), C(9A297BA4), C(9B2B7DAC),
	C(9C256F94), C(9D27699C), C(9E216384), C(9F23658C),
	C(A05DE769), C(A15FE161), C(A259EB79), C(A35BED71),
	C(A455FF49), C(A557F941), C(A651F359), C(A753F551),
	C(A84DD729), C(A94FD121), C(AA49DB39), C(AB4BDD31),
	C(AC45CF09), C(AD47C901), C(AE41C319), C(AF43C511),
	C(B07D87E9), C(B17F81E1), C(B2798BF9), C(B37B8DF1),
	C(B4759FC9), C(B57799C1), C(B67193D9), C(B77395D1),
	C(B86DB7A9), C(B96FB1A1), C(BA69BBB9), C(BB6BBDB1),
	C(BC65AF89), C(BD67A981), C(BE61A399), C(BF63A591),
	C(C09DBA4E), C(C19FBC46), C(C299B65E), C(C39BB056),
	C(C495A26E), C(C597A466), C(C691AE7E), C(C793A876),
	C(C88D8A0E), C(C98F8C06), C(CA89861E), C(CB8B8016),
	C(CC85922E), C(CD879426), C(CE819E3E), C(CF839836),
	C(D0BDDACE), C(D1BFDCC6), C(D2B9D6DE), C(D3BBD0D6),
	C(D4B5C2EE), C(D5B7C4E6), C(D6B1CEFE), C(D7B3C8F6),
	C(D8ADEA8E), C(D9AFEC86), C(DAA9E69E), C(DBABE096),
	C(DCA5F2AE), C(DDA7F4A6), C(DEA1FEBE), C(DFA3F8B6),
	C(E0DD7A53), C(E1DF7C5B), C(E2D97643), C(E3DB704B),
	C(E4D56273), C(E5D7647B), C(E6D16E63), C(E7D3686B),
	C(E8CD4A13), C(E9CF4C1B), C(EAC94603), C(EBCB400B),
	C(ECC55233), C(EDC7543B), C(EEC15E23), C(EFC3582B),
	C(F0FD1AD3), C(F1FF1CDB), C(F2F916C3), C(F3FB10CB),
	C(F4F502F3), C(F5F704FB), C(F6F10EE3), C(F7F308EB),
	C(F8ED2A93), C(F9EF2C9B), C(FAE92683), C(FBEB208B),
	C(FCE532B3), C(FDE734BB), C(FEE13EA3), C(FFE338AB)
};

static zuint32 const rc[19] = {
	C(BA542F74), C(53D3D24D), C(50AC8DBF), C(70529A4C),
	C(EAD597D1), C(33515BA6), C(DE48A899), C(DB32B7FC),
	C(E39E919B), C(E2BB416E), C(A5CB6B95), C(A1F3B102),
	C(CCC41D14), C(C363DA5D), C(5FDC7DCD), C(7F5A6C5C),
	C(F726FFED), C(E89D6F8E), C(19A0F089)
};


CIPHER_ANUBIS_API
void anubis_set_key(Anubis *object, zuint32 const *key, zusize key_size)
	{
	zsint n, cr, i, j, r;
	zuint32 k0, k1, k2, k3, v, kappa[MAXIMUM_N], inter[MAXIMUM_N];

	n = (zsint)((key_size * 8) >> 5);
	object->r = cr = 8 + n;

	/*------------------------------------------.
	| Map cipher key to initial key state (mu). |
	'------------------------------------------*/
	for (i = 0; i < n; i++) kappa[i] = z_uint32_big_endian(key[i]);

	/*----------------------------.
	| Generate cr + 1 round keys. |
	'----------------------------*/
	for (r = 0; r <= cr; r++)
		{
		/*--------------------------------.
		| Generate r-th round key cr ^ r. |
		'--------------------------------*/
		k0 = t4[ kappa[n - 1] >> 24	   ];
		k1 = t4[(kappa[n - 1] >> 16) & 0xFF];
		k2 = t4[(kappa[n - 1] >>  8) & 0xFF];
		k3 = t4[ kappa[n - 1]	     & 0xFF];

		for (i = n - 2; i >= 0; i--)
			{
			k0 = t4[(kappa[i] >> 24)] ^
			(t5[ k0 >> 24	     ] & C(FF000000)) ^
			(t5[(k0 >> 16) & 0xFF] & C(00FF0000)) ^
			(t5[(k0 >>  8) & 0xFF] & C(0000FF00)) ^
			(t5[ k0	       & 0xFF] & C(000000FF));

			k1 = t4[(kappa[i] >> 16) & 0xFF] ^
			(t5[ k1 >> 24	     ] & C(FF000000)) ^
			(t5[(k1 >> 16) & 0xFF] & C(00FF0000)) ^
			(t5[(k1 >>  8) & 0xFF] & C(0000FF00)) ^
			(t5[ k1	       & 0xFF] & C(000000FF));

			k2 = t4[(kappa[i] >>  8) & 0xFF] ^
			(t5[ k2 >> 24	     ] & C(FF000000)) ^
			(t5[(k2 >> 16) & 0xFF] & C(00FF0000)) ^
			(t5[(k2 >>  8) & 0xFF] & C(0000FF00)) ^
			(t5[ k2	       & 0xFF] & C(000000FF));

			k3 = t4[(kappa[i]) & 0xFF] ^
			(t5[ k3 >> 24	     ] & C(FF000000)) ^
			(t5[(k3 >> 16) & 0xFF] & C(00FF0000)) ^
			(t5[(k3 >>  8) & 0xFF] & C(0000FF00)) ^
			(t5[ k3	       & 0xFF] & C(000000FF));
			}

		object->e[r][0] = k0;
		object->e[r][1] = k1;
		object->e[r][2] = k2;
		object->e[r][3] = k3;

		/*----------------------------------------.
		| Compute kappa ^ {r + 1} from kappa ^ r. |
		'----------------------------------------*/
		if (r == cr) break;

		for (i = 0; i < n; i++)
			{
			j = i;
			inter[i]  = t0[ kappa[j--] >> 24	]; if (j < 0) j = n - 1;
			inter[i] ^= t1[(kappa[j--] >> 16) & 0xFF]; if (j < 0) j = n - 1;
			inter[i] ^= t2[(kappa[j--] >>  8) & 0xFF]; if (j < 0) j = n - 1;
			inter[i] ^= t3[ kappa[j  ]	  & 0xFF];
			}

		kappa[0] = inter[0] ^ rc[r];
		for (i = 1; i < n; i++) kappa[i] = inter[i];
		}

	/*---------------------------------------------------------------.
	| Generate inverse key schedule:				 |
	| K' ^ 0 = K ^ cr, K' ^ cr = K ^ 0, K' ^ r = theta(K ^ {cr - r}) |
	'---------------------------------------------------------------*/
	for (i = 0; i < 4; i++)
		{
		object->d[ 0][i] = object->e[cr][i];
		object->d[cr][i] = object->e[ 0][i];
		}

	for (r = 1; r < cr; r++) for (i = 0; i < 4; i++)
		{
		v = object->e[cr - r][i];

		object->d[r][i] =
		t0[t4[ v >> 24	      ] & 0xFF] ^
		t1[t4[(v >> 16) & 0xFF] & 0xFF] ^
		t2[t4[(v >>  8) & 0xFF] & 0xFF] ^
		t3[t4[ v	& 0xFF] & 0xFF];
		}
	}


static void cipher(
	zuint32	const  key[MAXIMUM_ROUND_COUNT + 1][4],
	zuint32 const* block,
	zusize	       block_size,
	zuint32*       output,
	zuint	       round_count
)
	{
	zsint r;
	zuint32 state[4];
	zuint32 inter[4];

	for (block_size >>= 4; block_size; block_size--, block += 4, output += 4)
		{
		/*------------------------------------------.
		| Map input block to cipher state (mu)	    |
		| and add initial round key (sigma[K ^ 0]). |
		'------------------------------------------*/
		state[0] = z_uint32_big_endian(block[0]) ^ key[0][0];
		state[1] = z_uint32_big_endian(block[1]) ^ key[0][1];
		state[2] = z_uint32_big_endian(block[2]) ^ key[0][2];
		state[3] = z_uint32_big_endian(block[3]) ^ key[0][3];

		/*-------------------.
		| R - 1 full rounds. |
		'-------------------*/
		for (r = 1; r < round_count; r++)
			{
			inter[0] =
			t0[state[0] >> 24] ^
			t1[state[1] >> 24] ^
			t2[state[2] >> 24] ^
			t3[state[3] >> 24] ^ key[r][0];

			inter[1] =
			t0[(state[0] >> 16) & 0xFF] ^
			t1[(state[1] >> 16) & 0xFF] ^
			t2[(state[2] >> 16) & 0xFF] ^
			t3[(state[3] >> 16) & 0xFF] ^ key[r][1];

			inter[2] =
			t0[(state[0] >> 8) & 0xFF] ^
			t1[(state[1] >> 8) & 0xFF] ^
			t2[(state[2] >> 8) & 0xFF] ^
			t3[(state[3] >> 8) & 0xFF] ^ key[r][2];

			inter[3] =
			t0[(state[0]) & 0xFF] ^
			t1[(state[1]) & 0xFF] ^
			t2[(state[2]) & 0xFF] ^
			t3[(state[3]) & 0xFF] ^ key[r][3];

			state[0] = inter[0];
			state[1] = inter[1];
			state[2] = inter[2];
			state[3] = inter[3];
			}

		/*-------------------------------------------------------.
		| Last round mapping cipher state to output (mu ^ {-1}). |
		'-------------------------------------------------------*/
		output[0] = z_uint32_big_endian
			((t0[(state[0] >> 24)] & C(FF000000)) ^
			 (t1[(state[1] >> 24)] & C(00FF0000)) ^
			 (t2[(state[2] >> 24)] & C(0000FF00)) ^
			 (t3[(state[3] >> 24)] & C(000000FF)) ^
			 key[round_count][0]);

		output[1] = z_uint32_big_endian
			((t0[(state[0] >> 16) & 0xFF] & C(FF000000)) ^
			 (t1[(state[1] >> 16) & 0xFF] & C(00FF0000)) ^
			 (t2[(state[2] >> 16) & 0xFF] & C(0000FF00)) ^
			 (t3[(state[3] >> 16) & 0xFF] & C(000000FF)) ^
			 key[round_count][1]);

		output[2] = z_uint32_big_endian
			((t0[(state[0] >> 8) & 0xFF] & C(FF000000)) ^
			 (t1[(state[1] >> 8) & 0xFF] & C(00FF0000)) ^
			 (t2[(state[2] >> 8) & 0xFF] & C(0000FF00)) ^
			 (t3[(state[3] >> 8) & 0xFF] & C(000000FF)) ^
			 key[round_count][2]);

		output[3] = z_uint32_big_endian
			((t0[state[0] & 0xFF] & C(FF000000)) ^
			 (t1[state[1] & 0xFF] & C(00FF0000)) ^
			 (t2[state[2] & 0xFF] & C(0000FF00)) ^
			 (t3[state[3] & 0xFF] & C(000000FF)) ^
			 key[round_count][3]);
		}
	}


CIPHER_ANUBIS_API
void anubis_encipher(Anubis *object, zuint32 const *block, zusize block_size, zuint32 *output)
	{cipher(object->e, block, block_size, output, object->r);}


CIPHER_ANUBIS_API
void anubis_decipher(Anubis *object, zuint32 const *block, zusize block_size, zuint32 *output)
	{cipher(object->d, block, block_size, output, object->r);}


#if defined(CIPHER_ANUBIS_BUILD_ABI) || defined(CIPHER_ANUBIS_BUILD_MODULE_ABI)

	CIPHER_ANUBIS_ABI ZCipherABI const abi_cipher_anubis = {
		/* test_key		 */ NULL,
		/* set_key		 */ (ZCipherSetKey )anubis_set_key,
		/* encipher		 */ (ZCipherProcess)anubis_encipher,
		/* decipher		 */ (ZCipherProcess)anubis_decipher,
		/* enciphering_size	 */ NULL,
		/* deciphering_size	 */ NULL,
		/* instance_size	 */ sizeof(Anubis),
		/* key_minimum_size	 */ ANUBIS_KEY_MINIMUM_SIZE,
		/* key_maximum_size	 */ ANUBIS_KEY_MAXIMUM_SIZE,
		/* key_word_size	 */ ANUBIS_KEY_WORD_SIZE,
		/* enciphering_word_size */ ANUBIS_WORD_SIZE,
		/* deciphering_word_size */ ANUBIS_WORD_SIZE,
		/* features		 */ FALSE
	};

#endif

#if defined(CIPHER_ANUBIS_BUILD_MODULE_ABI)

#	include <Z/ABIs/generic/module.h>

	static ZModuleUnit const unit = {
		"Anubis", "Anubis", Z_VERSION(1, 0, 0), &abi_cipher_anubis
	};

	static ZModuleDomain const domain = {"Cipher", Z_VERSION(1, 0, 0), 1, &unit};
	Z_API_WEAK_EXPORT ZModuleABI const __module_abi__ = {1, &domain};

#endif


/* Anubis.c EOF */
